home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 March: Reference Library / Dev.CD Mar 96 RL / Dev.CD Mar 96 RL.toast / Technical Documentation / develop / develop Issue 25 / develop Issue 25 code / FontToPict (Space Hack GX) / FontToPict.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-13  |  10.6 KB  |  386 lines  |  [TEXT/MPS ]

  1. // SpaceHack.c
  2. //
  3. // A sample that shows how to do the equivalent of the "space hack"
  4. // under QuickDraw GX, since that hack no longer works (and this
  5. // new method isn't a hack).
  6. //
  7. // The "Space Hack" is the technique of printing a single space (' ')
  8. // in a font in order to get that font resident on a printer so you
  9. // can use it directly from PostScript.
  10. //
  11. // Under QuickDraw GX, printing a space gets a font that consists solely
  12. // of a space on the printer, which isn't exactly what you wanted.
  13. //
  14. // The function FontToPict() is something you can drop into an app
  15. // which uses this technique. It checks for the presence of QuickDraw
  16. // GX, and calls the correct code. In the QuickDraw GX case, it calls
  17. // makePSHandle, which makes, surprisingly enough, a handle full of
  18. // PS (PostScript), which you can send to the printer by embedding it
  19. // in a PicComment, and calling DrawPicture on the resulting picture.
  20. //
  21. // MakePSHandle() builds an encoding array (if one isn't passed to it),
  22. // calls GXFlattenFont (via a wrapper function, FontToHandle), and
  23. // cleans up any messes.
  24.  
  25. #include <Memory.h>
  26. #include <QuickDraw.h>
  27. #include <Script.h>
  28. #include <ToolUtils.h>
  29. #include <GXFonts.h>
  30. #include <GXGraphics.h>
  31. #include <GXEnvironment.h>
  32. #include <Files.h>
  33. #include <Fonts.h>
  34. #include <StandardFile.h>
  35. #include <Gestalt.h>
  36. #include <Resources.h>
  37.  
  38. #include "exceptions.h"
  39.  
  40. typedef    struct {
  41.     gxSpoolBlock    spool;
  42.     long            reference;
  43.     long            position;
  44.     long            size;
  45.     void            *data;
  46.     void            *userField;
  47. } userSpool;
  48.  
  49. #define allocationIncrement 128
  50.  
  51. #define gestaltGXVersion            'qdgx'            // in PrintingManager.h (old) or GXPrinting.h (new)
  52. #define gestaltGXPrintingMgrVersion    'pmgr'            // in PrintingManager.h (old) or GXPrinting.h (new)
  53.  
  54. // our entrypoints
  55. PicHandle FontToPict(short qdFont, short qdStyle);    // returns a PICT suitable for printing
  56. OSErr MakePSHandle(short qdFont, char qdStyle, unsigned short *encodingArray, Handle *encHandle);
  57.  
  58. // utility functions
  59. static Handle FontToHandle(gxFont fontID, unsigned short encoding[]);
  60. static long    MakeMac8BitEncoding(gxFont theFont, unsigned short encoding[]);
  61. static gxFont ConvertQDFontToGXFont(short qdFont, short qdStyle);
  62. static void GetPostScriptFontName(gxFont fontID, Str255 fontName);
  63. static Boolean GXInstalled(void);
  64. static void InitToolbox(void);
  65. static void DumpHandleToFile(PicHandle data);
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73. void main(void)
  74. {
  75.     PicHandle    picture;
  76.     short    testFontRef = 0;    // put real font reference here
  77.     InitToolbox();
  78.  
  79.     picture = FontToPict(testFontRef, 0);
  80.     DumpHandleToFile(picture);
  81. }
  82.  
  83.  
  84.  
  85.  
  86. // return a pict that can be printed via DrawPicture
  87. // NOTE: You'd better have your grafPort setup before
  88. // calling this, or it'll blast the windowManager port
  89. PicHandle FontToPict(short qdFont, short qdStyle)
  90. {
  91.     Rect        theRect = {0, 0, 1, 1};
  92.     PicHandle    thePict = OpenPicture(&theRect);
  93.     const    short    kPostScriptHandle = 192;
  94.  
  95.     if (GXInstalled()) {    // If QuickDraw GX is present, use the new method
  96.         Handle    piccommentHdl;
  97.         // The following pointer would typically be set to an array
  98.         // of the characters you're going to use. For test purposes
  99.         // we're passing a nil, which say "Give me the whole font."
  100.         // actually specifying the encoding becomes critical for CJK
  101.         // fonts, since sending the whole umpty-thousand characters
  102.         // would be bad (Don't cross the beams!)
  103.         unsigned    short    *myEncoding = nil;
  104.         
  105.         MakePSHandle(qdFont,qdStyle,myEncoding,&piccommentHdl);
  106.         PicComment(kPostScriptHandle,GetHandleSize(piccommentHdl),piccommentHdl);
  107.     } else {                // if we don't have QuickDraw GX, use the old method
  108.         Point    penPoint;
  109.  
  110.         // we would normally set the clip here, but since we're just
  111.         // drawing a space, there's not really a need
  112.         GetPen(&penPoint);    // save the pen location
  113.         TextFont(qdFont);
  114.         TextFace(qdStyle);
  115.         DrawChar(' ');
  116.         MoveTo(penPoint.h,penPoint.v);    // restore the pen location
  117.     }
  118.  
  119.     ClosePicture();
  120.     return(thePict);
  121. }
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128. /**************************************************
  129.     Make a handle full of postscript font
  130. ***************************************************/
  131. OSErr MakePSHandle(short qdFont, char qdStyle, unsigned short *encodingArray, Handle *outputHandle)
  132. {
  133.     OSErr        status = noErr;
  134.     gxFont        theFont;
  135.     unsigned short        *myEncoding;
  136.     Boolean        madeEncoding = false;
  137.  
  138.     theFont = ConvertQDFontToGXFont(qdFont,qdStyle);    // convert to a gxFont
  139.  
  140.     if (!encodingArray) {
  141.         long    returnLength;
  142.  
  143.         myEncoding = (unsigned short *)NewPtrClear(256 * sizeof(short));
  144.         returnLength = MakeMac8BitEncoding(theFont, myEncoding);
  145.         if (returnLength != 256) {
  146.             DebugStr("\pHmm. We didn't get a full encoding.");
  147.             return(returnLength);    // pass the error along
  148.         }
  149.         madeEncoding = true;
  150.     } else {
  151.         myEncoding = encodingArray;
  152.     }
  153.  
  154.     *outputHandle = FontToHandle(theFont, myEncoding);
  155.  
  156.     if (madeEncoding) DisposePtr((Ptr)myEncoding);
  157.  
  158.     status = MemError();
  159.     if (status == noErr) {
  160.         status = GXGetGraphicsError(nil);
  161.         if (status != noErr) {
  162.             DisposeHandle(*outputHandle);
  163.             *outputHandle = nil;
  164.         }
  165.     }
  166.     return(status);
  167. }
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174. //
  175. // Utility functions
  176. //
  177. static Boolean GXInstalled(void)
  178. {
  179.     long version;
  180.  
  181.     if (Gestalt(gestaltGXVersion, &version) == noErr)
  182.         if (Gestalt(gestaltGXPrintingMgrVersion, &version) == noErr)
  183.             return(true);
  184.     return(false);
  185. }
  186.  
  187. // get the postScript unique name of the font. Return a C String.
  188. static void GetPostScriptFontName(gxFont fontID, Str255 fontName)
  189. {
  190.     long length;
  191.     length = GXFindFontName(fontID, gxPostscriptFontName, gxNoPlatform,
  192.         gxNoScript, gxNoLanguage, fontName, nil);
  193.  
  194.     // the PostScript name shouldn't ever be more than 255 characters
  195.     // long, but if it is, something has gone horribly awry. Best to
  196.     // at least detect the error, rather than let it propagate and
  197.     // trash something else.
  198.     if (length > 255) DebugStr("\pOOPS. We're dead in the water.");
  199.     else fontName[length]=0;    // string isn't terminated, so we do it
  200. }
  201.  
  202. static long HandleSpoolProc(gxSpoolCommand command,  userSpool *block)
  203. {
  204.     OSErr        status = noErr;
  205.     
  206.     switch (command)  {
  207.         case gxOpenReadSpool:
  208.             block->size = 0;
  209.             block->position = 0;
  210.             break;
  211.         case gxOpenWriteSpool:
  212.             block->data = NewHandle(allocationIncrement);
  213.             block->size = allocationIncrement;
  214.             block->position = 0;
  215.             status = MemError();
  216.             break;
  217.         case gxReadSpool:
  218.             BlockMove((*(char **) block->data) + block->position,
  219.                 block->spool.buffer,
  220.                 block->spool.count);
  221.             block->position += block->spool.count;
  222.             break;
  223.         case gxWriteSpool:
  224.             {
  225.                 register long oldPosition;
  226.                 
  227.                 oldPosition = block->position;
  228.                 block->position += block->spool.count;
  229.                 
  230.                 /* make sure there's room for one buffer past current pointer */
  231.                 if (block->position + block->spool.bufferSize > block->size) {
  232.                     block->size += block->spool.bufferSize;
  233.                     HUnlock((Handle) block->data);
  234.                     SetHandleSize((Handle) block->data, block->size);
  235.                     HLock((Handle) block->data);
  236.                     status = MemError();
  237.                 }
  238.                 if (status == noErr)
  239.                 BlockMove(block->spool.buffer,
  240.                     (*(char **) block->data + oldPosition),
  241.                     block->spool.count);
  242.             }
  243.             break;
  244.         case gxCloseSpool:
  245.             SetHandleSize((Handle) block->data, block->position);
  246.             status = MemError();
  247.             break;
  248.     } 
  249.     return(status);
  250. }
  251.  
  252. /***********************
  253.     Wrapper for call to GXFlattenFont to make it easier
  254.  
  255.     fontID:        the gxFont reference to use for making the encoding.
  256.     encoding:    The array of glyph codes indicating order
  257.                 and id's of glyphs to make encoding for.
  258. *************/
  259. static Handle FontToHandle(gxFont fontID, unsigned short encoding[256])
  260. {
  261.     userSpool        block;
  262.     scalerStream    stream;
  263.     Str255            fontName;
  264.     
  265.     block.spool.spoolProcedure = NewgxSpoolProc(HandleSpoolProc);
  266.     block.spool.buffer = nil;
  267.     block.spool.bufferSize = 0;
  268.     
  269.     stream.streamRefCon = fontID;
  270.     stream.types = type1StreamType;
  271. #if JUST_ENCODING
  272.     // Have font scaler make just an encoding for us
  273.     stream.action = encodingOnlyStreamAction;
  274. #else
  275.     // Get a downloadable font
  276.     stream.action = downloadStreamAction;
  277. #endif
  278.     stream.memorySize = 0;
  279.     stream.variationCount = selectAllVariations;
  280.     stream.variations = nil;
  281.     stream.info.font.encoding = encoding;
  282.     stream.info.font.glyphBits = nil;
  283.     
  284.     GetPostScriptFontName(fontID,fontName);
  285.  
  286.     stream.info.font.name = (char *)fontName;    // this should NOT be a pString
  287.  
  288.     // Call the scaler to generate the data for us.
  289.     GXFlattenFont(fontID, &stream, &block.spool);
  290.      
  291.     DisposeRoutineDescriptor(block.spool.spoolProcedure);
  292.     return (Handle) block.data;
  293. }
  294.  
  295.  
  296. /*******************************************************
  297.     Function: MakeMac8BitEncoding:
  298.     
  299.     Function sets up an encoding vector for the standard
  300.     Mac 8 bit encoding for the current active script system.
  301.     
  302.     theFont:    the font to make encoding for.
  303.     encoding:    array of 256 shorts, encoding will be returned
  304.                 in here.
  305.     returns:    The number of bytes encoded. (should always be 256)
  306. ********************************************************/
  307. static long MakeMac8BitEncoding(gxFont theFont, unsigned short encoding[])
  308. {
  309.     gxFontScript    theScript;
  310.     long            index;
  311.     unsigned char    theBytes[256];
  312.     long            length;
  313.     short            i;
  314.  
  315.     theScript = (gxFontScript)GetEnvirons(smSysScript) + 1;    // Quickdraw GX scripts are 1+scriptmgr scripts.
  316.  
  317.     // try system script first
  318.     index = GXFindFontEncoding(theFont, gxMacintoshPlatform, theScript, gxNoLanguage);
  319.     if(!index) {
  320.         // well, that didn't work. Try roman
  321.         index = GXFindFontEncoding(theFont, gxMacintoshPlatform, gxRomanScript, gxNoLanguage);
  322.     }
  323.  
  324.     /** Make the mac character set **/        
  325.     for (i = 0; i < 256; ++i)
  326.         theBytes[i] = i;
  327.  
  328.     /** Convert it to glyph codes **/
  329.     length = GXApplyFontEncoding(theFont, index, nil, theBytes, 256, encoding, nil);
  330.  
  331.     return(length);
  332. }
  333.  
  334. static gxFont ConvertQDFontToGXFont(short qdFont, short qdStyle)
  335. {
  336.     gxFont        theFont;
  337.     gxStyle theStyle = GXNewStyle();
  338.     GXConvertQDFont(theStyle, qdFont, qdStyle);
  339.     theFont = GXGetStyleFont(theStyle);
  340.     GXDisposeStyle(theStyle);
  341.     return(theFont);
  342. }
  343.  
  344. static void DumpHandleToFile(PicHandle data)
  345. {
  346.     StandardFileReply    reply;
  347.     Str255    defaultName = "\pFontDump";
  348.     Str255    prompt = "\pCreate font file";
  349.     short    fref;
  350.  
  351.     if (!data) return;
  352.  
  353.     StandardPutFile(prompt,defaultName,&reply);
  354.     if (reply.sfGood) {
  355.         if (reply.sfReplacing) FSpDelete(&(reply.sfFile));
  356.         FSpCreateResFile(&(reply.sfFile),'RSED','rsrc',reply.sfScript);
  357.         fref = FSpOpenResFile(&(reply.sfFile),fsRdWrPerm);
  358.         AddResource((Handle)data,'PICT',1,"\ptest picture");
  359.         UpdateResFile(fref);
  360.         CloseResFile(fref);
  361.     }
  362. }
  363.  
  364. static void InitToolbox(void)
  365. {
  366.     Handle        myMenuBar;
  367.     MenuHandle    appleMenu;
  368.     
  369.     InitGraf( &qd.thePort );
  370.     InitFonts();
  371.     FlushEvents( everyEvent, 0 );
  372.     InitWindows();
  373.     InitMenus();
  374.     TEInit();
  375.     InitDialogs( nil );
  376.     InitCursor();
  377.  
  378.     // this little demo doesn't use the menu bar, but hey
  379.     myMenuBar = GetNewMBar( 128 );
  380.     SetMenuBar( myMenuBar );
  381.     appleMenu = GetMHandle( 128 );
  382.     
  383.     AddResMenu( appleMenu, 'DRVR' );
  384.     DrawMenuBar();
  385. }
  386.